package chatController;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import chatGUI.*;
import chatModel.*;
import chatNI.ChatNI;
import java.io.File;
import java.io.IOException;
import signals.SignalTooBigException;

/**
 *
 * @author deepali and vansh
 */
public class ChatController {

    /**
     * @param cm The chat model instance that this chat controller manipulates
     * @param gui the graphic user interface that the client see and use it to
     * send and receive messages
     * @param ni the chat network interface is what allows the sending and the
     * receiving of different messages
     * @param filepath This is the file path of the file which is to be sent
     * @param buttonepressed It tell whether the user to which local user send
     * File Proposal has clicked on a button to accept or reject the file
     *
     */
    private ChatModel cm;
    private ChatGui gui;
    public ChatNI ni;
    private static String filepath;
    public boolean buttonpressed;

    /**
     * The chat controller is a part of the model view controller design pattern
     * that allows use to organize the chat system
     */
    public ChatController(ChatModel cm, ChatGui gui, ChatNI ni) {
        buttonpressed = false;
        this.cm = cm;
        this.gui = gui;
        this.ni = ni;
    }

    /**
     * This method sets button pressed which tells whether the user to which
     * local user send File Proposal has clicked on a button to accept or reject
     * the file
     */
    public void setbuttonpressed() {
        System.out.println("buttonpressed");
        buttonpressed = true;
    }

    public void releasebuttonpressed() {
        buttonpressed = false;
    }

    /**
     * This method is called when the client wants to get connected to the chat
     * system in this method we set the name of the the local user for this
     * instance of the chat system we start the listening msg thread on udp and
     * we send a hello
     *
     * @param username
     * @throws SignalTooBigException
     */
    public void performConnect(String username) throws SignalTooBigException {
        try {
            String s = username + "@" + ni.getLocalIPAdressString();
            User localUser = new User(s, InetAddress.getLocalHost().getHostName());
            cm.setLocalUser(localUser);
            cm.setLocalUserIsConnected(true);
            ni.startThread();
            ni.sendHello(s);
        } catch (UnknownHostException ex) {
            Logger.getLogger(ChatController.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    /**
     * This method allows us to disconnect from the chat system and allowing
     * other users to know that we are no longer connected and that they should
     * remove the local user from their users list
     *
     * @throws SignalTooBigException
     * @throws IOException
     */
    public void performDisconnect() throws SignalTooBigException, IOException {
        cm.setLocalUserIsConnected(false);
        ni.sendBye(cm.getLocalUser().getUsername());
    }

    /**
     * This method allows us to send a message to a specific user, we get the
     * user from the hashmap and then we send it using the network interface
     *
     * @param username
     * @param message
     * @throws SignalTooBigException
     */
    public void performSendMessage(String username, String message) throws SignalTooBigException {
        ni.sendMsg(username, message);
        Conversation c = cm.createConversation(cm.getHashmapUsers().get(username));
        cm.addConversations(c);

    }

    /**
     * This method allows us to add a tab in the graphic user interface when the
     * local user selects a remote user that is in the list of the connected
     * users
     *
     * @param username
     */
    public void performUserSelected(String username) {
        User remoteUser = cm.getHashmapUsers().get(username);
        System.out.println("performUserSelected");
        System.out.println(remoteUser.getUsername());
        Conversation c = new Conversation(remoteUser);
        cm.addConversations(c);
        System.out.println("we have to add a tab to the user we chose ");

        gui.addTab(c);
    }

    /**
     *
     */
    /**
     * This method allows us to add the remote user that sent us a hello; this
     * hello can be of a user that just got connected
     *
     * @param username which sent hello
     * @param hostname which sent hello
     */
    public void performHelloRcvd(String username, String hostname) {
        System.out.println("On receiving a hello");

        User newUser = new User(username, hostname);
        cm.addUserInList(newUser);
        System.out.println(username + " is added to the list");
    }

    /**
     * This method allows us to add the remote user that sent us a hello; this
     * hello can be of a user that was already connected.
     *
     * @param username which send helloOK
     * @param hostname which sent helloOK
     */
    public void performHelloOKRcvd(String username, String hostname) {
        System.out.println("On receiving a helloOK(Controller)");
        User newUser = new User(username, hostname);
        cm.addUserInList(newUser);
        System.out.println(username + " is added to the list");
    }

    /**
     * This method is called when we receive a message , we check if this is the
     * beginning of a conversation if this is the case then we add a tab in the
     * graphical interface and we add the message if the message have been
     * already started we content with delivering the message
     *
     * @param remoteUser user to whom we have to send the message
     * @param msg String we have to send
     */
    public void performMsgRcvd(User remoteUser, String msg) {
        Conversation c = cm.getHashmapConv().get(remoteUser);
        String username = remoteUser.getUsername();
        if (c != null) {
            cm.addConversations(c);

        } else {
            c = cm.createConversation(remoteUser);
            gui.addTab(cm.getHashmapConv().get(remoteUser));
            cm.addConversations(c);
        }
        for (int i = 0; i < gui.getChatwindow().tabbedPane.getTabCount(); i++) {
            if ((remoteUser.getUsername() + "@" + remoteUser.getHostname()).equalsIgnoreCase(gui.getChatwindow().tabbedPane.getTitleAt(i))) {
                gui.getChatwindow().tabbedPane.setSelectedIndex(i);
                System.out.println("SelectedIndex" + i);
                break;
            }

            System.out.println("Atindex" + i);
            System.out.println("remoteUser" + remoteUser.getHostname());
            System.out.println(gui.getChatwindow().tabbedPane.getTitleAt(i));

        }

        gui.getChatwindow().addMessagercvd(msg, remoteUser.getUsername());

    }

    /**
     * performNotifybeforeFileReception method allows us to notify the user that
     * he might receive a file
     *
     * @param username this is the remote user name of the person to whom we
     * want to send the file
     */
    public void performNotifybeforeFileReception(String username) {

        Conversation c = cm.getHashmapConv().get(username);
        User remoteUser = cm.getHashmapUsers().get(username);
        if (c != null) {
            System.out.println("Here1");
            cm.addConversations(c);
        } else {
            System.out.println("Here2");
            c = cm.createConversation(remoteUser);
            System.out.println("Here5");
            gui.addTab(cm.getHashmapConv().get(remoteUser));
            System.out.println("Here6");
            cm.addConversations(c);
            System.out.println("Here7");
        }
        System.out.println("Here3");
        gui.getChatwindow().notifyBeforFileSent(username);
        System.out.println("Here4");
    }

    /**
     * performFileReceived method allows us to notify the local user that he
     * received a file and that it is in his local folder
     *
     * @param username this is the remote user name of the person to whom we
     * want to send the file
     */
    public void performFileReceived(String username) {
        gui.getChatwindow().notifyFileRcvd(username);
    }

    /**
     * performFileSent method allows us to notify the local user that the file
     * sent
     *
     * @param username this is the remote user name of the person to whom we
     * want to send the file
     */
    public void performFileSent(String username) {
        gui.getChatwindow().notifyFileSent(username);
    }

    /**
     * performSendFileRequest method allows us to send a file request before
     * sending a file to give the choice to the remote user to receive or refuse
     * the file
     *
     * @param username this is the remote user name of the person to whom we
     * want to send the file
     * @param filename this is the file name that we would like to send
     * @param filepath this the file path of the file that we are going to send
     * @param username
     * @param filename
     * @param filepath
     * @throws SignalTooBigException
     * @throws IOException
     */
    public void performSendFileRequest(String username, String filename, String filepath) throws SignalTooBigException, IOException {
        System.out.println("Here one must send the notification at the check chat ");
        this.filepath = filepath;
        File file = new File(filepath);
        long size = file.length();
        ni.sendFileRequest(username, filename, size);
        Conversation c = cm.getHashmapConv().get(cm.getHashmapUsers().get(username));
        cm.addConversations(c);
    }

    /**
     * performSendFileAnswerRcvd method allows us to send a file after knowing
     * that the remote user have accepted for us to send him the file
     *
     * @param username this is the remote user name of the person to whom
     * @param hostname this is hostname of that user
     * @param ip ip of that user
     * @throws UnknownHostException
     */
    public void performFileAnswerRcvd(String hostname, InetAddress ip) throws UnknownHostException {
        for (User user : cm.getHashmapConv().keySet()) {

            if (user.getHostname().equals(hostname)) {
                User u_req = user;
                String username = u_req.getUsername();
                System.out.println(username);
                this.updateUserList(username);
                System.out.println("Entered performFileAnswerRcvd in Chat Controller");
                performSendFile(username, ip, this.filepath);

                break;

            }
        }

    }

    /**
     * performSendFile method allows us to send a file and calling the method
     * that allows us to send the file in the chat network class
     *
     * @param username this is the remote user name of the person to whom we
     * want to send the file
     * @param ip is the ip address of that remote user
     * @param filepath this the file path of the file that we are going to send
     */
    public void performSendFile(String username, InetAddress ip, String filepath) throws UnknownHostException {
        System.out.println("In PerformSendFile Chat Controller with username =" + username);
        ni.sendFile(this.filepath, ip, username);
        Conversation c = cm.getHashmapConv().get(cm.getHashmapUsers().get(username));
        cm.addConversations(c);
    }

    /**
     * performFileRequestRcvd method allows us to open a window to ask the local
     * user if he wants to receive the file or not
     *
     * @param username this is the remote user name of the person to whom we
     * want to send the file
     * @param filename this the file name of the file that we are going to send
     */
    public void performFileRequestRcvd(String username, String filename) {
        System.out.println("Ans");
        gui.FileWindow(username, filename);
        while (buttonpressed == false) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
            }
        }
    }

    /**
     * performSendFileAnswer method allows us to answer the remote user that we
     * accept him/her to send a file
     *
     * @param username this is the remote user name of the person to whom we
     * want to send the file
     * @param filename this the file name of the file that we are going to send
     * @param accepted tell if user accepted or rejected the FileProposal
     */
    public void performSendFileAnswer(String username, String filename, boolean accepted) {
        String message;

        Conversation c = cm.getHashmapConv().get(cm.getHashmapUsers().get(username));
        cm.addConversations(c);
        if (accepted) {
            User user = cm.getHashmapUsers().get(username);
            ni.sendFileAnswer(user, filename, accepted);
        }
        cm.addConversations(c);

    }

    /**
     * When a Bye is received, we remove the remote user from which we received
     * the bye from the list we then remove him from the list of the users
     *
     * @param remoteUser the user which sent a bye and is disconnecting
     */
    public void performByeRcvd(User remoteUser) {
        cm.removeUserFromList(remoteUser);
        String username = remoteUser.getUsername();
        gui.getChatwindow().removeUser(remoteUser.getUsername());
        Conversation c = cm.getHashmapConv().get(remoteUser);
        if (c != null) {
            cm.addConversations(c);
        }
    }

    /**
     * When we send the bye, we close the chat window
     */
    public void performByeSent() {
        gui.close();
    }

    /**
     * This method updates the user list and adds the username to the list if
     * its not already present
     *
     * @param username is the username which has to be rpesent in the list of
     * connected users
     */
    public void updateUserList(String username) {
        Conversation c = cm.getHashmapConv().get(cm.getHashmapUsers().get(username));
        cm.addConversations(c);
    }

}
